home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Mark Pilgrim / MSG Demo 1.4 / source / Shell ƒ / graphics.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-30  |  13.2 KB  |  346 lines  |  [TEXT/KAHL]

  1. /**********************************************************************\
  2.  
  3. File:        graphics.c
  4.  
  5. Purpose:    This module handles opening/closing/updating all windows:
  6.             this includes manipulating offscreen GWorlds & bitmaps
  7.             for fun and profit.
  8.  
  9. This program is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 2 of the License, or
  12. (at your option) any later version.
  13.  
  14. This program is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. GNU General Public License for more details.
  18.  
  19. You should have received a copy of the GNU General Public License
  20. along with this program in a file named "GNU General Public License".
  21. If not, write to the Free Software Foundation, 675 Mass Ave,
  22. Cambridge, MA 02139, USA.
  23.  
  24. \**********************************************************************/
  25.  
  26. #include "graphics.h"
  27. #include "about.h"
  28. #include "about MSG.h"
  29. #include "help.h"
  30. #include "dialogs.h"
  31. #include "error.h"
  32. #include "menus.h"
  33. #include "environment.h"
  34. #include "prefs.h"
  35. #include "program globals.h"
  36. #include "demo.h"
  37.  
  38. WindowPtr        gTheWindow[NUM_WINDOWS];            /* windowptr of nth window */
  39. ExtendedWindowDataHandle
  40.                 gTheWindowData[NUM_WINDOWS];        /* handle to nth window data struct */
  41.  
  42. /* internal global variables for use by graphics.c only */
  43. static    Rect        gBoundsRect[NUM_WINDOWS];        /* rectangle of offscreen bitmap */
  44. static    Rect        gMainScreenBounds;                /* bounds of main monitor */
  45. static    GWorldPtr    gTheGWorld[NUM_WINDOWS];        /* offscreen graphics world */
  46. static    int            gOffscreenDepth[NUM_WINDOWS];    /* pixel depth of offscreen GWorld */
  47. static    Ptr            gBWBitMap[NUM_WINDOWS];            /* offscreen bitmap for B/W machines */
  48. static    GrafPort    gBWGrafPort[NUM_WINDOWS];        /* offscreen grafport "  "     "     */
  49. static    GrafPtr        gBWGrafPtr[NUM_WINDOWS];        /* offscreen grafptr  "  "     "     */
  50.  
  51.  
  52. Boolean InitTheGraphics(void)
  53. {
  54.     int                i;
  55.     
  56.     GetMainScreenBounds();
  57.     
  58.     for (i=0; i<NUM_WINDOWS; i++)
  59.     {
  60.         /* nothing is inited; if there's an error later on, we'll know how much to */
  61.         /* clean up in ShutDownTheGraphics() */
  62.         gTheWindow[i]=gTheGWorld[i]=gTheWindowData[i]=0L;
  63.     }
  64.     
  65.     for (i=0; i<NUM_WINDOWS; i++)
  66.     {
  67.         gTheWindowData[i]=(ExtendedWindowDataHandle)NewHandle(sizeof(ExtendedWindowDataRec));
  68.         if (gTheWindowData[i]==0L)                            /* return if error */
  69.             return FALSE;
  70.         
  71.         (**(gTheWindowData[i])).offscreenNeedsUpdate=TRUE;    /* offscreen not inited */
  72.         (**(gTheWindowData[i])).windowIndex=i;                /* so we can retrieve it O(1) */
  73.     }
  74.     
  75.     /* set window dispatch routines */
  76.     (**(gTheWindowData[kAbout])).dispatchProc=AboutBoxDispatch;        /* see about.c */
  77.     (**(gTheWindowData[kHelp])).dispatchProc=HelpWindowDispatch;    /* see help.c */
  78.     (**(gTheWindowData[kAboutMSG])).dispatchProc=AboutMSGBoxDispatch;/* see about MSG.c */
  79.     
  80.     /* call window dispatch routines with "startup" message */
  81.     ((**(gTheWindowData[kAbout])).dispatchProc)(gTheWindowData[kAbout], kStartup, 0L);
  82.     ((**(gTheWindowData[kHelp])).dispatchProc)(gTheWindowData[kHelp], kStartup, 0L);
  83.     ((**(gTheWindowData[kAboutMSG])).dispatchProc)(gTheWindowData[kAboutMSG], kStartup, 0L);
  84.     
  85.     return TRUE;
  86. }
  87.  
  88. void OpenTheWindow(int index)
  89. {
  90.     if (!gTheWindow[index])        /* if window exists, we'll just update it (see below) */
  91.     {
  92.         if (((**(gTheWindowData[index])).dispatchProc)    /* call window's dispatch to */
  93.                 (gTheWindowData[index], kInitialize, 0L)==kFailure)    /* initialize it */
  94.         {        /* default is to center window on main screen */
  95.             (**(gTheWindowData[index])).initialTopLeft.h =
  96.                 gMainScreenBounds.left + (((gMainScreenBounds.right -
  97.                 gMainScreenBounds.left) - (**(gTheWindowData[index])).windowWidth) / 2);
  98.             (**(gTheWindowData[index])).initialTopLeft.v =
  99.                 gMainScreenBounds.top + (((gMainScreenBounds.bottom -
  100.                 gMainScreenBounds.top) - (**(gTheWindowData[index])).windowHeight) / 2);
  101.         }
  102.         
  103.         (**(gTheWindowData[index])).windowBounds.left=
  104.             (**(gTheWindowData[index])).initialTopLeft.h;
  105.         
  106.         (**(gTheWindowData[index])).windowBounds.top=
  107.             (**(gTheWindowData[index])).initialTopLeft.v;
  108.             
  109.         if (((**(gTheWindowData[index])).windowType==noGrowDocProc) ||
  110.             ((**(gTheWindowData[index])).windowType==documentProc) ||
  111.             ((**(gTheWindowData[index])).windowType==movableDBoxProc) ||
  112.             ((**(gTheWindowData[index])).windowType==zoomDocProc) ||
  113.             ((**(gTheWindowData[index])).windowType==zoomNoGrow) ||
  114.             ((**(gTheWindowData[index])).windowType==rDocProc))
  115.                 (**(gTheWindowData[index])).windowBounds.top += 9;    /* compensate for title */
  116.         
  117.         /* don't put window over menu bar */
  118.         if ((**(gTheWindowData[index])).windowBounds.top < GetMBarHeight()+1)
  119.             (**(gTheWindowData[index])).windowBounds.top = GetMBarHeight()+1;
  120.         
  121.         (**(gTheWindowData[index])).windowBounds.bottom =
  122.             (**(gTheWindowData[index])).windowBounds.top +
  123.             (**(gTheWindowData[index])).windowHeight;
  124.         
  125.         (**(gTheWindowData[index])).windowBounds.right =
  126.             (**(gTheWindowData[index])).windowBounds.left +
  127.             (**(gTheWindowData[index])).windowWidth;
  128.         
  129.         if (gHasColorQD)
  130.         {
  131.             HLock(gTheWindowData[index]);    /* important!  NewCWindow may move memory */
  132.             /* create the color window with our specs, see IM Essentials 4-79ff */
  133.             gTheWindow[index] = NewCWindow(0L, &((**(gTheWindowData[index])).windowBounds),
  134.                 (**(gTheWindowData[index])).windowTitle, FALSE,
  135.                 (**(gTheWindowData[index])).windowType, (WindowPtr)-1L,
  136.                 (**(gTheWindowData[index])).hasCloseBox,
  137.                 (unsigned long)gTheWindowData[index]);
  138.             HUnlock(gTheWindowData[index]);    /* no sense keeping it locked now */
  139.         }
  140.         else
  141.         {
  142.             HLock(gTheWindowData[index]);    /* important!  NewWindow may move memory */
  143.             /* create the B/W window with our specs, see IM Essentials 4-82ff */
  144.             gTheWindow[index] = NewWindow(0L, &((**(gTheWindowData[index])).windowBounds),
  145.                 (**(gTheWindowData[index])).windowTitle, FALSE,
  146.                 (**(gTheWindowData[index])).windowType, (WindowPtr)-1L,
  147.                 (**(gTheWindowData[index])).hasCloseBox,
  148.                 (unsigned long)gTheWindowData[index]);
  149.             HUnlock(gTheWindowData[index]);    /* no sense keeping it locked now */
  150.         }
  151.     }
  152.     
  153.     if (gTheWindow[index])
  154.     {
  155.         ShowWindow(gTheWindow[index]);            /* immediately show this new window */
  156.         SelectWindow(gTheWindow[index]);        /* immediately select this new window */
  157.         /* call window's dispatch routine to alert it that it's open now */
  158.         ((**(gTheWindowData[index])).dispatchProc)(gTheWindowData[index], kOpen, 0L);
  159.         SetPort(gTheWindow[index]);                /* important! */
  160.         UpdateTheWindow(gTheWindowData[index]);    /* immediately update this new window */
  161.     }
  162.     else HandleError(kNoMemory, FALSE);            /* if unsuccessful, display error */
  163. }
  164.  
  165. void GetMainScreenBounds(void)
  166. {
  167.     gMainScreenBounds = screenBits.bounds;        /* low-mem global */
  168.     gMainScreenBounds.top += GetMBarHeight();    /* don't include menu bar */
  169. }
  170.  
  171. int GetWindowDepth(ExtendedWindowDataHandle theData)
  172. {
  173.     int                index;
  174.     
  175.     index=(**theData).windowIndex;
  176.     /* if Color Quickdraw is not available, the depth must be 1. */
  177.     /* if Color Quickdraw is available and the window exists, return the window's
  178.        GWorld's graphics device's pixel map's pixel depth */
  179.     /* if Color Quickdraw is available and the window does not exist, return the
  180.        pixel depth of the main screen */
  181.     return (gHasColorQD) ? ((gTheWindow[index]) ?
  182.             (**(**(GetGWorldDevice(gTheGWorld[index]))).gdPMap).pixelSize :
  183.             (**(**GetMainDevice()).gdPMap).pixelSize) : 1;
  184. }
  185.  
  186. void UpdateTheWindow(ExtendedWindowDataHandle theData)
  187. {
  188.     int                index;
  189.     GWorldPtr        currentGWorld;
  190.     GDHandle        currentGDHandle;
  191.     long            offRowBytes, sizeOfOff;
  192.     
  193.     index=(**theData).windowIndex;
  194.     gBoundsRect[index]=gTheWindow[index]->portRect;
  195.     OffsetRect(&gBoundsRect[index], -gBoundsRect[index].left, -gBoundsRect[index].top);
  196.  
  197.     if (gWhichWipe!=0)
  198.         (**theData).offscreenNeedsUpdate=TRUE;
  199.     
  200.     if (gHasColorQD)    /* w/o Color Quickdraw, GWorlds may not be supported */
  201.     {
  202.         if (gTheGWorld[index]==0L)        /* create new graphics world if none exists */
  203.         {
  204.             /* try to create new graphics world; display error if unsuccessful */
  205.             if (NewGWorld(&gTheGWorld[index], 0, &gBoundsRect[index], 0L, 0L, 0)!=0)
  206.             {
  207.                 HandleError(kNoMemory, FALSE);
  208.                 return;
  209.             }
  210.             gOffscreenDepth[index]=GetWindowDepth(theData);    /* keep track of pixel depth */
  211.             NoPurgePixels(GetGWorldPixMap(gTheGWorld[index]));    /* never purge our pixmap! */
  212.         }
  213.         
  214.         GetGWorld(¤tGWorld, ¤tGDHandle);    /* get current settings */
  215.         LockPixels(GetGWorldPixMap(gTheGWorld[index]));    /* important!  copybits may move mem */
  216.         /* update offscreen graphics world, compensating for change in pixel depth */
  217.         UpdateGWorld(&gTheGWorld[index], 0, &gBoundsRect[index], 0L, 0L, 0);
  218.         SetGWorld(gTheGWorld[index], 0L);                /* set to our offscreen gworld */
  219.  
  220.         if (gOffscreenDepth[index]!=GetWindowDepth(theData))    /* if pixel depth changed */
  221.         {
  222.             gOffscreenDepth[index]=GetWindowDepth(theData);        /* save new depth */
  223.             (**theData).offscreenNeedsUpdate=TRUE;                /* we'll need to redraw */
  224.         }
  225.     }
  226.     else    /* deal with (guaranteed) B/W bitmaps manually */
  227.     {
  228.         if (gBWGrafPtr[index]==0L)    /* create new offscreen bitmap if none exists */
  229.         {
  230.             gBWGrafPtr[index]=&gBWGrafPort[index];
  231.             OpenPort(gBWGrafPtr[index]);    /* make a new port */
  232.             
  233.             /* calculate the size of the offscreen bitmap from the boundsrect */
  234.             offRowBytes=(((gBoundsRect[index].right-gBoundsRect[index].left)+15)>>4)<<1;
  235.             sizeOfOff=(long)(gBoundsRect[index].bottom-gBoundsRect[index].top)*offRowBytes;
  236.             
  237.             gBWBitMap[index]=NewPtr(sizeOfOff);        /* allocate space for bitmap */
  238.             if (gBWBitMap[index]==0L)                /* abort if unsuccessful */
  239.             {
  240.                 ClosePort(gBWGrafPtr[index]);        /* cleaning up... */
  241.                 gBWGrafPtr[index]=0L;
  242.                 HandleError(kNoMemory, FALSE);        /* displaying error... */
  243.                 return;                                /* and aborting... */
  244.             }
  245.             
  246.             gBWGrafPort[index].portBits.baseAddr=gBWBitMap[index];    /* --> our bitmap */
  247.             gBWGrafPort[index].portBits.rowBytes=offRowBytes;        /* bitmap size */
  248.             gBWGrafPort[index].portBits.bounds=                        /* bitmap bounds */
  249.                 gBWGrafPort[index].portRect=gBoundsRect[index];            
  250.         }
  251.         
  252.         SetPort(gBWGrafPtr[index]);                    /* set port for subsequent drawing */
  253.     }    
  254.     
  255.     if ((**theData).offscreenNeedsUpdate)            /* if we need to redraw */
  256.     {
  257.         (**theData).offscreenNeedsUpdate=FALSE;        /* not anymore */
  258.         /* call window's dispatch and tell it to redraw itself */
  259.         ((**theData).dispatchProc)(theData, kUpdate, GetWindowDepth(theData));
  260.     }
  261.     
  262.     if (gHasColorQD)
  263.         SetGWorld(currentGWorld, currentGDHandle);    /* restore old settings */
  264.     
  265.     SetPort(gTheWindow[index]);                        /* set to window to draw to */
  266.     /* copy offscreen bitmap from graphics world or bitmap to onscreen window */
  267.     if (gWhichWipe!=0)
  268.         WipeDispatch(gHasColorQD ? (GrafPtr)gTheGWorld[index] : 
  269.                     gBWGrafPtr[index], gTheWindow[index], gBoundsRect[index]);
  270.     else
  271.         CopyBits(gHasColorQD ? &(((GrafPtr)gTheGWorld[index])->portBits) :
  272.                     &(gBWGrafPtr[index]->portBits), &(gTheWindow[index]->portBits),
  273.                     &gBoundsRect[index], &gBoundsRect[index], 0, 0L);
  274.     
  275.     if (gHasColorQD)
  276.         UnlockPixels(GetGWorldPixMap(gTheGWorld[index]));    /* remember we locked these? */
  277.     
  278.     ValidRect(&(gTheWindow[index]->portRect));        /* so we don't reupdate */
  279. }
  280.  
  281. Boolean CloseTheWindow(ExtendedWindowDataHandle theData)
  282. {
  283.     int                index;
  284.     
  285.     index=(**theData).windowIndex;
  286.     
  287.     /* if the window's dispatch cancels the close, abort */
  288.     if (((**theData).dispatchProc)(theData, kClose, 0L)==kCancel)
  289.         return FALSE;
  290.     
  291.     DisposeWindow(gTheWindow[index]);    /* get rid of the actual window in memory */
  292.     gTheWindow[index]=0L;                /* so _we_ know the window doesn't exist */
  293.     
  294.     /* tell window's dispatch that it's disposed of now */
  295.     ((**theData).dispatchProc)(theData, kDispose, 0L);
  296.     
  297.     return TRUE;    /* successful close */
  298. }
  299.  
  300. void DrawThePicture(PicHandle *thePict, int whichPict, int x, int y)
  301. /* a standard routine for loading a picture (if necessary) and then drawing it */
  302. {
  303.     Rect            temp;
  304.     
  305.     if (*thePict==0L)        /* get it if it doesn't exist */
  306.         *thePict=(PicHandle)GetPicture(whichPict);
  307.     
  308.     HLock(*thePict);        /* lock it down for dereferencing to get picture bounds */
  309.     temp.top=y;
  310.     temp.left=x;
  311.     temp.bottom=temp.top+(***thePict).picFrame.bottom-(***thePict).picFrame.top;
  312.     temp.right=temp.left+(***thePict).picFrame.right-(***thePict).picFrame.left;
  313.     DrawPicture(*thePict, &temp);    /* draw picture at (x,y) */
  314.     HUnlock(*thePict);        /* unlock for better memory management */
  315. }
  316.  
  317. Boolean ReleaseThePict(PicHandle thePict)
  318. {
  319.     if (thePict!=0L)    /* if exists, release it */
  320.     {
  321.         ReleaseResource(*thePict);
  322.         return TRUE;
  323.     }
  324.     else return FALSE;
  325. }
  326.  
  327. void ShutDownTheGraphics(void)
  328. {
  329.     int                i;
  330.     
  331.     /* send shutdown messages to the shell's windows */
  332.     ((**(gTheWindowData[kAbout])).dispatchProc)(gTheWindowData[kAbout], kShutdown, 0L);
  333.     ((**(gTheWindowData[kHelp])).dispatchProc)(gTheWindowData[kHelp], kShutdown, 0L);
  334.     ((**(gTheWindowData[kAboutMSG])).dispatchProc)(gTheWindowData[kAboutMSG], kShutdown, 0L);
  335.     
  336.     for (i=0; i<NUM_WINDOWS; i++)                /* technically, none of this cleanup */
  337.     {                                            /* is necessary, since these are all */
  338.         if (gTheGWorld[i]!=0L)                    /* in the application heap, which is */
  339.             DisposeGWorld(gTheGWorld[i]);        /* about to get trashed when we quit */
  340.         if (gTheWindowData[i]!=0L)                /* anyway, but it's still good to Do */
  341.             DisposeHandle(gTheWindowData[i]);    /* The Right Thing™ even if it kills */
  342.         if (gTheWindow[i]!=0L)                    /* you in the process (:             */
  343.             DisposeWindow(gTheWindow[i]);
  344.     }
  345. }
  346.